﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Bettzueche.RLGlue.TaskSpec {

    /// <summary>
    /// Factory methods to get a TaskSpec instance.<para>
    /// See <a href="http://glue.rl-community.org/wiki/Task_Spec">Task Spec Wiki</a> for details.</para>
    /// </summary>
    public class TaskSpecFactory {

        /// <summary>
        /// Gets a default TaskSpec (V3.0).
        /// </summary>
        /// <returns></returns>
        public static ITaskSpec GetTaskSpec() {
            return new TaskSpecV30();
        }

        /// <summary>
        /// Gets the task spec.
        /// </summary>
        /// <param name="version">The version.</param>
        /// <param name="problemType">Type of the problem.</param>
        /// <param name="discount">The discount factor.</param>
        /// <param name="obs">The observation reanges.</param>
        /// <param name="acts">The action ranges.</param>
        /// <param name="rewRange">the reward range</param>
        /// <param name="extra">The extra string.</param>
        /// <returns>A TaskSpec Instance of the specified Version (RL-Glue-3.n or 2).
        /// Null, if one parameter is null or the specified Version is not supported</returns>
        public static ITaskSpec GetTaskSpec(String version, String problemType, double discount, RLTypesSpec obs, RLTypesSpec acts, DoubleRange rewRange, String extra) {
            if (version == null)
                return null;
            if (version.StartsWith("RL-Glue-3."))
                return TaskSpecFactory.GetTaskSpec(problemType,discount,obs,acts,rewRange,extra);
            if (version.StartsWith("2")) {
                try {
                    return new TaskSpecV20(obs, acts, rewRange);
                }
                catch (Exception) {
                    return null;
                }
            }
            else
                return null;
                //throw new NotSupportedException("The specified version "+version+"is not supported.");
        }

        /// <summary>
        /// Gets the task spec.<para>
        /// null parameters will not be applyed, so you can pass on null to get an default value.</para>
        /// </summary>
        /// <param name="problemType">Type of the problem.</param>
        /// <param name="discount">The discount factor.</param>
        /// <param name="obs">The observation reanges.</param>
        /// <param name="acts">The action ranges.</param>
        /// <param name="rewRange">the reward range</param>
        /// <param name="extra">The extra string.</param>
        /// <returns>A RL-Glue-3.0 TaskSpec Instance</returns>
        public static ITaskSpec GetTaskSpec(String problemType, double discount, RLTypesSpec obs, RLTypesSpec acts, DoubleRange rewRange, String extra) {
            TaskSpecV30 result = new TaskSpecV30();
            Debug.WriteLineIf(!(problemType == "episodic" || problemType == "continuing"),
                "TaskSpecFactory.GetTaskSpec: " + problemType + " is not standard.","Warning");
            if (problemType != null)
                result.Propblemtype = problemType;
            Debug.Assert(0 <= discount && discount <= 1, "TaskSpecFactory.GetTaskSpec: Discount factor is " + discount + ",but should be in [0,1]");
            result.Discountfactor = discount;
            if (obs != null)
                result.Observations = obs;
            if (acts != null)
                result.Actions = acts;
            if (extra != null)
                result.Extra = extra;
            if (rewRange != null)
                result.Reward = rewRange;

            return result;
        }

        /// <summary>
        /// Gets the task spec.
        /// </summary>
        /// <param name="taskSpecString">The task spec string.</param>
        /// <returns>The TaskSpec Instance or null, if deserialisation failed.</returns>
        /// <remarks>
        /// Supported TaskSpecs: V2.0 & RL-Glue-3.0
        /// </remarks>
        public static ITaskSpec GetTaskSpec(String taskSpecString) {
            ITaskSpec result = null;
            ITaskSpecSerializer serializer = new TaskSpecV30Serializer();
            result = serializer.Deserialize(taskSpecString);
            if (result == null) {
                serializer = new TaskSpecV2Serializer();
                result = serializer.Deserialize(taskSpecString);
            }
            return result;
        }

        ///// <summary>
        ///// Gets the default serializer.
        ///// </summary>
        ///// <returns>Default Task Spec Serializer</returns>
        //public static ITaskSpecSerializer GetSerializer() {
        //    throw new NotImplementedException("Not implemented yet");
        //}

        ///// <summary>
        ///// Gets the serializer corresponding to the tsType.
        ///// </summary>
        ///// <param name="tsType">Type of the <see cref="ITaskSpec"/>.</param>
        ///// <returns>Task Spec Serializer</returns>
        //public static ITaskSpecSerializer GetSerializer(Type tsType) {
        //    throw new NotImplementedException("Not implemented yet");
        //}
    }
}
